前面 26 天我們把 RAG 系統的每個環節都拆解、實作、優化了一遍,從今天開始要進入最後階段:把這些程式碼整合成一個真正可以被使用者操作的系統。
目前為止的程式碼大多是腳本形式,第一步是把整套邏輯包裝成一個 Web API,方便前端或其他服務呼叫。
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class QueryRequest(BaseModel):
question: str
chat_history: list = []
class QueryResponse(BaseModel):
answer: str
sources: list
@app.post("/query", response_model=QueryResponse)
def query_rag(request: QueryRequest):
# 1. 問題改寫(若有對話歷史,套用 Day 19 的技巧)
rewritten_question = rewrite_with_history(request.chat_history, request.question) \
if request.chat_history else request.question
# 2. 檢索(套用 Day 15-20 的優化技巧)
retrieved = hybrid_search(rewritten_question, top_k=20)
reranked = rerank_results(rewritten_question, retrieved, top_k=5)
# 3. 生成(套用 Day 21 的 Prompt 設計)
system_prompt, user_prompt = build_rag_prompt(request.question, reranked)
answer = call_llm(system_prompt, user_prompt)
return QueryResponse(
answer=answer,
sources=[{"content": c["content"][:100], "metadata": c["metadata"]} for c in reranked]
)
uvicorn main:app --reload --port 8000
from fastapi.responses import StreamingResponse
@app.post("/query/stream")
def query_rag_stream(request: QueryRequest):
def generate():
for chunk in call_llm_stream(system_prompt, user_prompt):
yield chunk
return StreamingResponse(generate(), media_type="text/plain")
async function askQuestion(question) {
const response = await fetch("http://localhost:8000/query", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ question, chat_history: [] }),
});
const data = await response.json();
displayAnswer(data.answer, data.sources);
}
前端介面設計上,建議至少包含:
實際上線的系統,需要處理各種異常情況:
@app.post("/query", response_model=QueryResponse)
def query_rag(request: QueryRequest):
try:
retrieved = hybrid_search(request.question, top_k=20)
if not retrieved:
return QueryResponse(answer="很抱歉,目前查無相關資訊。", sources=[])
# ... 正常流程
except Exception as e:
logger.error(f"查詢發生錯誤:{e}")
return QueryResponse(answer="系統暫時發生問題,請稍後再試。", sources=[])
把 RAG 邏輯封裝成標準的 API 服務,是讓系統從「一支可以跑的腳本」變成「真正能被使用者操作的產品」的關鍵一步。明天我們要討論上線後不可避免要面對的問題:效能、延遲與成本。